/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.controller.project;

import cn.ac.nercis.pes.common.constant.project.SecurityLevel;
import cn.ac.nercis.pes.common.utils.ConvertUtils;
import cn.ac.nercis.pes.community.component.controls.PesTextField;
import cn.ac.nercis.pes.community.component.dialog.MessageDialog;
import cn.ac.nercis.pes.community.component.dialog.MessageType;
import cn.ac.nercis.pes.community.constant.SaveMethod;
import cn.ac.nercis.pes.community.controller.base.GlobalEventHandle;
import cn.ac.nercis.pes.community.mapper.project.SystemViewMapper;
import cn.ac.nercis.pes.community.model.vo.project.SystemVO;
import cn.ac.nercis.pes.community.support.FXMLController;
import cn.ac.nercis.pes.community.utils.ControlUtils;
import cn.ac.nercis.pes.community.utils.*;
import cn.ac.nercis.pes.community.views.project.TaskManageView;
import cn.ac.nercis.pes.model.dto.project.SystemDTO;
import cn.ac.nercis.pes.model.dto.project.SystemDetailDTO;
import cn.ac.nercis.pes.model.dto.project.SystemEvaluationDTO;
import cn.ac.nercis.pes.service.project.SystemService;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.net.URL;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;


/**
 * 添加系统管理控制器
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@FXMLController
public class AddSystemController implements Initializable, GlobalEventHandle {
    @FXML
    private StackPane page;
    @FXML
    private Label titleLabel;
    @FXML
    private Button saveButton;
    @FXML
    private Button saveAndButton;
    @FXML
    private Button backButton;
    @FXML
    private PesTextField nameTF;
    @FXML
    private TextArea descTF;
    @FXML
    private ToggleGroup gradeProtectionGroup;
    @FXML
    private ToggleGroup serviceRangeGroup;
    @FXML
    private ToggleGroup serviceObjectGroup;
    @FXML
    private ToggleGroup coverageGroup;
    @FXML
    private ToggleGroup paSchemeGroup;
    @FXML
    private ToggleGroup ppSituationGroup;

    @FXML
    private RadioButton selectLevelRb;
    @FXML
    private RadioButton unselectLevelRb;
    @FXML
    private TextField securityLevelTxt;
    @FXML
    private TextField sLevelTxt;
    @FXML
    private TextField aLevelTxt;
    @FXML
    private TextField gLevelTxt;
    @FXML
    private ComboBox<String> reqLevelCbx;

    @FXML
    private TextField filingNumberTxt;

    @FXML
    private RadioButton selectSameRb;
    @FXML
    private RadioButton unselectSame;
    @FXML
    private TextField changeDescTxt;

    @FXML
    private ToggleGroup ciiGroup;


    @FXML
    private ToggleGroup cloudGroup;

    @FXML
    private ToggleGroup cloudSelectGroup;


    private final SystemService systemService;
    private final SystemVO systemData = new SystemVO();
    private final BooleanProperty notEditModel = new SimpleBooleanProperty(false);

    private String projectId;
    private SystemEvaluationDTO systemEvaluation;

    @Autowired
    public AddSystemController(SystemService systemService) {
        this.systemService = systemService;
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        titleLabel.setGraphic(IconUtils.getGlyph("system-icon","title-icon"));
        saveButton.setGraphic(IconUtils.getGlyph("save-button-icon","btn-icon"));
        saveAndButton.setGraphic(IconUtils.getGlyph("save-two-button-icon","btn-icon"));
        backButton.setGraphic(IconUtils.getGlyph("back-button-icon","btn-icon"));
        this.initializeControl();
        GuiStore.applyQuickSave(this.page,this::onGlobalSave);
    }

    /**
     * 初始化数据
     * @param projectId 项目ID
     */
    public void initializeData(String projectId){
        //新增模式
        notEditModel.set(true);
        this.projectId = projectId;
        //初始化验证信息
        resetValidation();
        SystemDetailDTO systemDetail = SystemDetailDTO.builder().build();
        this.initSystemData(systemDetail);
        this.initSystemEvaluationData(systemDetail.getSystemEvaluation());
    }

    public void initializeData(SystemDTO systemDTO){
        //编辑模式
        notEditModel.set(false);
        //初始化验证信息
        resetValidation();
        CompletableFuture.supplyAsync(()->this.systemService.findById(systemDTO.getId()))
                .thenAccept(res->Platform.runLater(()->{
                    if(res.isSuccess()){
                        projectId = res.getData().getProjectId();
                        this.initSystemData(res.getData());
                        this.initSystemEvaluationData(res.getData().getSystemEvaluation());
                    }else{
                        MessageDialog.builder()
                                .withType(MessageType.FAIL)
                                .withMessage(res.getMsg())
                                .build();
                        this.saveButton.setVisible(false);
                    }
                }));
    }

    private void resetValidation(){
        this.nameTF.resetValidation();
    }

    private void initializeControl() {
        this.nameTF.textProperty().bindBidirectional(systemData.nameProperty());
        this.descTF.setText(systemData.getDesc());
        this.gLevelTxt.textProperty().addListener((o, oldVal, newVal) -> gLevelChange(newVal));
        this.sLevelTxt.textProperty().addListener((o,oldVal,newVal)->sOraLevelChange(newVal, aLevelTxt.getText(),"S"));
        this.aLevelTxt.textProperty().addListener((o,oldVal,newVal)->sOraLevelChange(newVal, sLevelTxt.getText(),"A"));


        this.sLevelTxt.disableProperty().bind(selectLevelRb.selectedProperty().not());
        this.aLevelTxt.disableProperty().bind(selectLevelRb.selectedProperty().not());
        this.selectSameRb.disableProperty().bind(selectLevelRb.selectedProperty().not());
        this.unselectSame.disableProperty().bind(selectLevelRb.selectedProperty().not());
        this.filingNumberTxt.disableProperty().bind(selectLevelRb.selectedProperty().not());
        this.changeDescTxt.disableProperty().bind(selectLevelRb.selectedProperty().not().and(unselectSame.selectedProperty().not()));

        this.reqLevelCbx.getItems().clear();
        SecurityLevel.getSupportLevels().forEach(sl->{
            this.reqLevelCbx.getItems().add(sl.getName());
        });
        this.reqLevelCbx.disableProperty().bind(unselectLevelRb.selectedProperty().not());
    }

    private void gLevelChange(String newValue){
        if(StringUtils.isEmpty(newValue)){
            return;
        }
        try {
            SecurityLevel level = SecurityLevel.fromLevel(Integer.parseInt(newValue));
            if (level == SecurityLevel.DEFAULT) {
                MessageDialog.builder()
                        .withType(MessageType.WARN)
                        .withMessage("网络安全等级保护定级G级别无效，当前只支持2、3、4级")
                        .build().show();
                gLevelTxt.setText("");
            } else {
                securityLevelTxt.setText(level.getName());
            }
        }catch (NumberFormatException ignore){
            MessageDialog.builder()
                    .withType(MessageType.FAIL)
                    .withMessage("网络安全等级保护定级G级别数据类型错误")
                    .build().show();
        }
    }

    private void sOraLevelChange(String newValue,String otherValue,String tag){
        if(StringUtils.isEmpty(newValue)){
            return;
        }
        try {
            SecurityLevel level = SecurityLevel.fromLevel(Integer.parseInt(newValue));
            if (level == SecurityLevel.DEFAULT) {
                MessageDialog.builder()
                        .withType(MessageType.WARN)
                        .withMessage(String.format("网络安全等级保护定级%s级别无效，当前只支持2、3、4级",tag))
                        .build().show();
            } else {
                var otherLevel = ConvertUtils.toInteger(otherValue);
                if(level.getLevel()>otherLevel){
                    gLevelTxt.setText(String.valueOf(level.getLevel()));
                }else{
                    gLevelTxt.setText(String.valueOf(otherLevel));
                }
            }
        }catch (NumberFormatException ignore){
            MessageDialog.builder()
                    .withType(MessageType.FAIL)
                    .withMessage(String.format("网络安全等级保护定级%s级别数据类型错误",tag))
                    .build().show();
        }
    }

    private void initSystemData(SystemDetailDTO systemDetail){
        this.systemData.setId(systemDetail.getId());
        this.systemData.setName(systemDetail.getName());
        this.systemData.setDesc(systemDetail.getDesc());
        this.descTF.setText(systemDetail.getDesc());

        this.selectLevelRb.setSelected(StringUtils.isEmpty(systemDetail.getReqLevel()));
        this.unselectLevelRb.setSelected(StringUtils.isNotEmpty(systemDetail.getReqLevel()));
        if(this.selectLevelRb.isSelected() && Objects.nonNull(systemDetail.getSecurityLevel())){
            if(systemDetail.getSecurityLevel() == SecurityLevel.DEFAULT){
                this.securityLevelTxt.setText("");
                this.sLevelTxt.setText("");
                this.aLevelTxt.setText("");
                this.gLevelTxt.setText("");
            }else{
                this.securityLevelTxt.setText(systemDetail.getSecurityLevel().getName());
                this.sLevelTxt.setText(String.valueOf(systemDetail.getSLevel()));
                this.aLevelTxt.setText(String.valueOf(systemDetail.getALevel()));
                this.gLevelTxt.setText(String.valueOf(systemDetail.getGLevel()));
            }
            this.filingNumberTxt.setText(systemDetail.getFilingNumber());
        }else{
            this.reqLevelCbx.getItems().stream()
                    .filter(s-> StringUtils.equals(s,systemDetail.getReqLevel()))
                    .findFirst()
                    .ifPresent(i->reqLevelCbx.getSelectionModel().select(i));
        }
    }

    private void initSystemEvaluationData(SystemEvaluationDTO systemEvaluation){
        this.systemEvaluation = systemEvaluation;
        if(this.selectLevelRb.isSelected()){
            this.selectSameRb.setSelected(Objects.nonNull(systemEvaluation.getIsChange()) && systemEvaluation.getIsChange());
            this.unselectSame.setSelected(Objects.isNull(systemEvaluation.getIsChange()) || (!systemEvaluation.getIsChange()));
            if (this.unselectSame.isSelected()) {
                this.changeDescTxt.setText(systemEvaluation.getChangeDesc());
            } else {
                this.changeDescTxt.setText("");
            }
        }else{
            this.selectSameRb.setSelected(false);
            this.unselectSame.setSelected(false);
            this.changeDescTxt.setText("");
        }
    }

    @FXML
    private void onBack(){
        var taskManageView = SpringUtils.getBean(TaskManageView.class).getView();
        GuiStore.setMainBodyContent(taskManageView);
        SpringUtils.getBean(TaskManageController.class).reloadSystemList();
    }

    @FXML
    public void onSave(){
        saveSystem(SaveMethod.SAVE);
    }

    @FXML
    public void onSaveAnd(){
        saveSystem(SaveMethod.SAVE_CONTINUE);
    }

    @Override
    public void onGlobalSave(){
        saveSystem(SaveMethod.GLOBAL_SAVE);
    }

    public BooleanProperty notEditModelProperty(){
        return this.notEditModel;
    }

    public boolean isNotEditModel(){
        return this.notEditModel.get();
    }

    private void saveSystem(SaveMethod method){
        systemData.setName(StringUtils.trim(this.systemData.getName()));
        if(!this.nameTF.validate()){
            return;
        }
        systemData.setDesc(this.descTF.getText());
        SystemDetailDTO systemDetailDTO = SystemViewMapper.INSTANCE.toDTO(systemData);
        systemDetailDTO.setProjectId(projectId);
        try {
            collectSystemDetailData(systemDetailDTO);
            collectSystemEvaluationData(systemDetailDTO);
        }catch (Exception ex){
            AppUtils.showMessageDialog(ex.getMessage(),MessageType.FAIL,this.page);
            log.error("收集数据期间出错：",ex);
            return;
        }
        CompletableFuture.supplyAsync(()->systemService.save(systemDetailDTO))
                .thenAccept(res-> Platform.runLater(()->{
                    if(res.isSuccess()){
                        AppUtils.showMessageDialog("保存成功",MessageType.SUCCESS,this.page);
                        if(method == SaveMethod.SAVE_CONTINUE){
                            //继续添加系统
                            initializeData(projectId);
                        }else if(method == SaveMethod.GLOBAL_SAVE){
                            //重新加载当前内容
                            initializeData(res.getData());
                        }else{
                            //返回到任务管理页面
                            onBack();
                        }
                    }else{
                        AppUtils.showMessageDialog(res.getMsg(),MessageType.FAIL,this.page);
                    }
                }));
    }

    private void collectSystemDetailData(SystemDetailDTO systemDetail) throws Exception{
        if(unselectLevelRb.isSelected()){
            if(Objects.isNull(reqLevelCbx.getValue()) || StringUtils.isBlank(reqLevelCbx.getValue())){
                reqLevelCbx.requestFocus();
                throw new Exception("请选择信息系统密码应用基本要求等级！");
            }
            systemDetail.setReqLevel(reqLevelCbx.getValue());
            systemDetail.setSecurityLevel(SecurityLevel.fromName(reqLevelCbx.getValue()));
        }else{
            systemDetail.setReqLevel("");
            systemDetail.setSLevel(ControlUtils.toInteger(sLevelTxt,"网络安全等级保护定级S级别数据类型错误"));
            systemDetail.setALevel(ControlUtils.toInteger(aLevelTxt,"网络安全等级保护定级A级别数据类型错误"));
            systemDetail.setGLevel(ControlUtils.toInteger(gLevelTxt,"网络安全等级保护定级G级别数据类型错误"));
            systemDetail.setSecurityLevel(SecurityLevel.fromLevel(systemDetail.getGLevel()));
            systemDetail.setFilingNumber(filingNumberTxt.getText());
        }
        if(systemDetail.getSecurityLevel() == SecurityLevel.DEFAULT){
            throw new Exception("当前网络安全等级保护定级只支持二、三、四级");
        }
    }

    private void collectSystemEvaluationData(SystemDetailDTO systemDetail) throws Exception{
        if(Objects.isNull(this.systemEvaluation)){
            this.systemEvaluation = new SystemEvaluationDTO();
        }
        systemDetail.setSystemEvaluation(this.systemEvaluation);
        if(selectLevelRb.isSelected()){
            systemEvaluation.setIsChange(selectSameRb.isSelected());
            systemEvaluation.setChangeDesc("");
            if(unselectSame.isSelected()){
                systemEvaluation.setChangeDesc(changeDescTxt.getText());
            }
        }else{
            systemEvaluation.setIsChange(false);
            systemEvaluation.setChangeDesc("");
        }
    }

}